using System;
using System.IO;
using System.Text;

namespace IppServer.Host.Ipp
{
    internal static class IppRequestParser
    {
        public static IppRequest Parse(byte[] payload)
        {
            if (payload == null || payload.Length < 8)
            {
                throw new InvalidDataException("IPP payload too small.");
            }

            var request = new IppRequest();
            var cursor = 0;

            request.Version = ReadUInt16(payload, ref cursor);
            var operationCode = ReadUInt16(payload, ref cursor);
            // 如果操作码 >= 0x4000，这是响应操作码，应该忽略或记录
            if (operationCode >= 0x4000)
            {
                throw new InvalidDataException($"收到响应操作码 0x{operationCode:X4}，这不是请求。");
            }
            request.Operation = (IppOperation)operationCode;
            request.RequestId = ReadInt32(payload, ref cursor);

            string lastName = null;
            while (cursor < payload.Length)
            {
                var tag = payload[cursor++];
                if (tag == 0x03) // end-of-attributes-tag
                {
                    // 遇到结束标记，文档数据从下一个字节开始
                    break;
                }

                if (tag >= 0x01 && tag <= 0x0F)
                {
                    // 属性组标签（operation-attributes-tag, job-attributes-tag 等）
                    lastName = null;
                    continue;
                }

                if (cursor + 4 > payload.Length)
                {
                    throw new InvalidDataException("Malformed IPP attribute header.");
                }

                var nameLength = ReadUInt16(payload, ref cursor);
                if (nameLength > 0)
                {
                    if (cursor + nameLength > payload.Length)
                    {
                        throw new InvalidDataException("Malformed IPP attribute name.");
                    }
                    lastName = Encoding.ASCII.GetString(payload, cursor, nameLength);
                    cursor += nameLength;
                }

                var valueLength = ReadUInt16(payload, ref cursor);
                if (cursor + valueLength > payload.Length)
                {
                    throw new InvalidDataException("Malformed IPP attribute value.");
                }

                var value = new byte[valueLength];
                Buffer.BlockCopy(payload, cursor, value, 0, valueLength);
                cursor += valueLength;

                request.Attributes.Add(new IppAttribute
                {
                    Tag = tag,
                    Name = lastName ?? string.Empty,
                    RawValue = value
                });
            }

            // 在 end-of-attributes-tag (0x03) 之后的所有数据都是文档数据
            if (cursor < payload.Length)
            {
                var documentLength = payload.Length - cursor;
                if (documentLength > 0)
                {
                    var document = new byte[documentLength];
                    Buffer.BlockCopy(payload, cursor, document, 0, documentLength);
                    request.DocumentData = document;
                }
            }

            return request;
        }

        private static ushort ReadUInt16(byte[] buffer, ref int cursor)
        {
            var value = (ushort)((buffer[cursor] << 8) + buffer[cursor + 1]);
            cursor += 2;
            return value;
        }

        private static int ReadInt32(byte[] buffer, ref int cursor)
        {
            var value = (buffer[cursor] << 24) +
                        (buffer[cursor + 1] << 16) +
                        (buffer[cursor + 2] << 8) +
                        buffer[cursor + 3];
            cursor += 4;
            return value;
        }
    }
}

